package xyz.xtt.user.config;

import static java.util.stream.Collectors.joining;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.util.pattern.PathPattern;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import cn.hutool.core.util.ClassUtil;
import xyz.xtt.user.client.UserClient;

@Component
public class CommandLineUrl implements CommandLineRunner {
	@Autowired
	private RequestMappingHandlerMapping requestMappingHandlerMapping;

	@Override
	public void run(String... args) throws Exception {
	}

	public Set<String> printAllUrlMappings() {
		Set<String> urls = new HashSet<>();
		Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
		handlerMethods.forEach((k, v) -> {
			PathPatternsRequestCondition patternsCondition = k.getPathPatternsCondition();
			Set<PathPattern> patterns = patternsCondition.getPatterns();
			String url = patterns.stream().map(x -> x.getPatternString()).collect(joining());
			urls.add(url);
		});
		return urls;
	}

	public static <T> Set<String> feignClientUrls(Class clazz) {
		Set<String> urls = new HashSet<>();
		Method[] methods = clazz.getMethods();
		for (Method method : methods) {
			PostMapping post = method.getAnnotation(PostMapping.class);
			if (Objects.nonNull(post)) {
				String url = post.value()[0];
				urls.add(url);
			}
			GetMapping get = method.getAnnotation(GetMapping.class);
			if (Objects.nonNull(get)) {
				String url = get.value()[0];
				urls.add(url);
			}
		}
		return urls;
	}

	private static String methodUrls(Method method) {
		PostMapping post = method.getAnnotation(PostMapping.class);
		if (Objects.nonNull(post)) {
			String url = post.value()[0];
			return url;
		}
		GetMapping get = method.getAnnotation(GetMapping.class);
		if (Objects.nonNull(get)) {
			String url = get.value()[0];
			return url;
		}
		RequestMapping req = method.getAnnotation(RequestMapping.class);
		if (Objects.nonNull(req)) {
			String url = req.value()[0];
			return url;
		}
		return StringUtils.EMPTY;
	}

	private static Set<String> methodsUrls(String baseUrl, Method[] methods) {
		Set<String> urls = new HashSet<>();
		for (Method method : methods) {
			String methodUrls = methodUrls(method);
			if (StringUtils.isBlank(methodUrls)) {
				continue;
			}
			String allUrl = baseUrl + methodUrls;
			urls.add(allUrl);
		}
		return urls;
	}

	public static void main(String[] args) {
		Set<String> controllUrls = Sets.newHashSet();
		Map<String, Set<String>> controllerUrlMap = Maps.newHashMap();
		Set<Class<?>> scanPackage = ClassUtil.scanPackage("xyz.xtt.user");
		for (Class<?> clazz : scanPackage) {
			RestController rest = clazz.getAnnotation(RestController.class);
			RequestMapping rqeu = clazz.getAnnotation(RequestMapping.class);
			if (Objects.nonNull(rest) && Objects.nonNull(rqeu)) {
				String value = rqeu.value()[0];
				Method[] methods = clazz.getMethods();
				Set<String> methdoUrls = methodsUrls(value, methods);
				controllerUrlMap.put(clazz.getSimpleName(), methdoUrls);
				controllUrls.addAll(methdoUrls);
			}
		}
		System.out.println("=====================================> controllUrls");
		controllUrls.stream().sorted().forEach(System.out::println);
		System.out.println("=====================================> feignClientUrls");
		Set<String> feignClientUrls = feignClientUrls(UserClient.class);
		feignClientUrls.stream().sorted().forEach(System.out::println);
		System.out.println(feignClientUrls.size());
		System.out.println("=====================================> filter");
		feignClientUrls.stream().filter(x -> !controllUrls.contains(x)).forEach(System.out::println);
	}
}
